package com.harvest.scientific.ladder.base

import android.content.Context
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import androidx.annotation.CallSuper
import androidx.annotation.LayoutRes
import androidx.annotation.MainThread
import androidx.appcompat.widget.LinearLayoutCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.*
import androidx.viewbinding.ViewBinding
import com.harvest.scientific.ladder.R
import com.harvest.scientific.ladder.databinding.CommonFragmentContainerBinding
import com.harvest.scientific.ladder.dialog.LoadingDialog
import com.harvest.scientific.ladder.ext.launchOnMain
import com.harvest.scientific.ladder.ext.visible
import com.harvest.scientific.ladder.util.LogUtils
import com.harvest.scientific.ladder.widget.BaseActionBar
import io.reactivex.Single
import io.reactivex.SingleEmitter
import java.lang.reflect.ParameterizedType

interface IFragment {

    fun getTitle(): String

    fun loadData()
}

abstract class BaseFragment<VB: ViewBinding>() : Fragment(),
    ILoading, IFragment {
        
    companion object {
        const val TAG = "BaseFragment"
    }

    protected var isViewCreated = false
    protected val viewCreatedSingleEmitters by lazy { mutableListOf<SingleEmitter<Boolean>>() }
    private var containerId = 0
    protected lateinit var _binding: VB

    fun checkSelfPermission(ctx: Context, permissions: Array<String?>): Boolean {
        var isAllGranted = true
        for (permission in permissions) {
            if (ContextCompat.checkSelfPermission(
                    ctx.applicationContext,
                    permission!!
                )
                != PackageManager.PERMISSION_GRANTED
            ) {
                isAllGranted = false
                break
            }
        }
        return isAllGranted
    }

    override fun getTitle(): String {
        return ""
    }

    override fun loadData() {
    }

    override fun dismissLoading() {
        loadingDialog?.dismiss()
    }
    private var loadingDialog: LoadingDialog? = null

    override fun showLoading() {
        loadingDialog ?: run {
            loadingDialog = LoadingDialog.Builder(requireActivity())
                .setIconType(LoadingDialog.Builder.ICON_TYPE_LOADING)
                .create()
        }

        loadingDialog?.show()
    }

    open fun onKeyEvent(keyCode: Int?, event: KeyEvent?): Boolean? {
        return false
    }

    protected open fun isActive(): Boolean {
        return null != activity && activity?.isFinishing == false
    }

    override fun onDestroyView() {
        super.onDestroyView()
    }

    @CallSuper
    @MainThread
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        isViewCreated = true
        launchOnMain(1) {
            viewCreatedSingleEmitters.forEach {
                if (!it.isDisposed) it.onSuccess(false)
            }
            viewCreatedSingleEmitters.clear()
        }
        initPage()
    }

    protected open fun initPage() {

    }

    protected lateinit var _parentBinding: CommonFragmentContainerBinding

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        createViewBinding()
        _parentBinding = CommonFragmentContainerBinding.inflate(inflater)
        if (isShowActionbar()) {
            setStatus(_parentBinding.baseActionBar)
        } else {
            _parentBinding.baseActionBar.setVisible(false)
        }

        _parentBinding.root.addView(_binding.root, RelativeLayout.LayoutParams(-1, -2).apply {
            addRule(RelativeLayout.BELOW, _parentBinding.baseActionBar.id)
        })
        _parentBinding.bgIv.visible(isShowBg())
        return _parentBinding.root
    }

    protected open fun isShowBg(): Boolean {
        return false
    }

    protected open fun isShowActionbar(): Boolean {
        return true
    }

    protected open fun setStatus(actionBar: BaseActionBar) {


    }


    //反射创建ViewBinding
    open protected fun createViewBinding() {

        val clazz: Class<*> =  (this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<VB>

        try {
            _binding = clazz.getMethod(
                "inflate", LayoutInflater::class.java
            ).invoke(null, layoutInflater) as VB

        } catch (e: Exception) {
            e.printStackTrace()
            throw IllegalArgumentException("无法通过反射创建ViewBinding对象")
        }

    }
    protected fun withViewCreated(): Single<Boolean> {
        return Single.create {
            if (isViewCreated) {
                if (isActive()) {
                    it.onSuccess(true)
                }
            } else {
                viewCreatedSingleEmitters.add(it)
            }
        }
    }


    
    open fun getContainerId(): Int {
        return containerId
    }

    open fun setContainerId(containerId: Int) {
        this.containerId = containerId
    }

    override fun onResume() {
        super.onResume()
        if (userVisibleHint) {
            onUserVisibleChanged(true)
        }
    }

    override fun onPause() {
        super.onPause()
    }

    override fun onDetach() {
        super.onDetach()
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
    }

    override fun onDestroy() {
        super.onDestroy()
    }

    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        if (isResumed) {
            onUserVisibleChanged(isVisibleToUser)
        }
    }

    open fun onUserVisibleChanged(isVisibleToUser: Boolean) {

    }

    open fun isVisibleToUser(): Boolean {
        return isResumed && userVisibleHint
    }
}

inline fun <reified VM : ViewModel> Fragment.viewModelFromActivity() =
    viewModels<VM>({ requireActivity() })